#include "../../src/detail/command_impl.hh"
#include "../../src/detail/command_manager.hh"
#include "../../src/detail/http_base_impl.hh"
#include "../../src/repo/src/include/root/coroutine/coroutine.h"
#include "../../src/util/os_util.hh"
#include "../../src/util/time_util.hh"
#include "../framework/unittest.hh"
#include <fstream>

FIXTURE_BEGIN(test_command_manager)

using namespace kratos;

SETUP([]() {});

CASE(TestStart1) {
  kratos::service::CommandManager manager(nullptr);
  ASSERT_TRUE(manager.start());
  manager.stop();
}

CASE(TestWaitFor1) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    return "done";
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"test\"}", 1000,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) {
                          done1 = call.lock()->get_content() == "done";
                        });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor2) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    throw std::runtime_error("");
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"test\"}", 1000,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) {
                          done1 = call.lock()->get_content() ==
                                  "{\"error\" : \"Internal error\"}";
                        });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor3) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    coro_yield();
    return "";
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"test\"}", 1000,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) { done1 = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(!done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor4) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  auto result = cmd.wait_for(
      "", 0, [&](const std::string &req) -> std::string { return ""; });
  manager.stop();
  http.stop();
  ASSERT_FALSE(result);
}

CASE(TestWaitFor5) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    return "";
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": sdjkfjsdkfjdkfj}", 1000,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) { done1 = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(!done);
  ASSERT_TRUE(done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor6) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"sdjkfjsdkfjdkfj\"}", 1000,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) { done1 = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor7) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    coro_yield();
    return "";
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"test\"}", 500,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) { done1 = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 1000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(!done1);
  manager.stop();
  http.stop();
}

CASE(TestWaitFor8) {
  kratos::service::CommandManager manager(nullptr);
  kratos::http::HttpBaseImpl http(nullptr);
  ASSERT_TRUE(manager.start());
  ASSERT_TRUE(http.start());
  kratos::service::CommandImpl cmd(&manager);
  bool done = false;
  cmd.wait_for("test", 1000, [&](const std::string &req) -> std::string {
    done = true;
    coro_yield();
    return "";
  });
  bool done1 = false;
  http.do_request_async("127.0.0.1", 6889, "/", "GET", {},
                        "{\"command\": \"test\"}", 200,0,
                        [&](kratos::http::HttpCallPtr call, std::uint64_t) { done1 = true; });
  auto start = util::get_os_time_millionsecond();
  while (true) {
    auto ms = util::get_os_time_millionsecond();
    manager.update(ms);
    http.update(ms);
    coro_sched();
    if (ms - start > 2000) {
      break;
    }
  }
  ASSERT_TRUE(done);
  ASSERT_TRUE(!done1);
  manager.stop();
  http.stop();
}

TEARDOWN([]() {});

FIXTURE_END(test_command_manager)
